package com.quick.im.client.handler;

import com.power.common.util.DateTimeUtil;
import com.quick.im.common.entity.message.MessageInfo;
import com.quick.im.common.proto.Message;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.nio.NioEventLoopGroup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;


@Slf4j
@Component
public class NettyClientHandler extends ChannelInboundHandlerAdapter {


    private ConcurrentHashMap<String, Message> pendingMessages = new ConcurrentHashMap<>();

    private static ChannelHandlerContext channelHandlerContext;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 客户端连接成功时，发送Protobuf消息
        UUID uuid = UUID.randomUUID();
        Message message = Message.newBuilder()
                .setMessageType(4)
                .setContent(uuid.toString())
                .setTimestamp(DateTimeUtil.nowStrTime())
                .build();
        channelHandlerContext = ctx;
        // 发送序列化后的字节数组
        ctx.writeAndFlush(message.toByteArray());
    }

    /**
     * send message
     * @param messageInfo
     */
    public void sendMessage(MessageInfo messageInfo) {
        Message message = Message.newBuilder()
                .setMessageType(Long.parseLong( messageInfo.getMessageType()))
                .setContent(messageInfo.getContent())
                .setTimestamp(DateTimeUtil.nowStrTime())

                .build();
        pendingMessages.put(messageInfo.getMessageId(), message);
        channelHandlerContext.writeAndFlush(message);
        scheduleResend(messageInfo,message);
    }

    /**
     * retry send message
     * @param messageInfo
     * @param msg
     */
    private void scheduleResend(MessageInfo messageInfo,Message msg) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        ScheduledFuture<?> future = group.schedule(() -> {
            if (messageInfo.incrementRetryCount() > 3) {
                log.error("Message failed after 3 retries: {}" , messageInfo.getMessageId());
                pendingMessages.remove(messageInfo.getMessageId());
            } else {
                log.info("Resending message:{} " ,messageInfo.getMessageId());
                channelHandlerContext.writeAndFlush(msg);
                scheduleResend(messageInfo,msg);
            }
        }, 5, TimeUnit.SECONDS);

        messageInfo.setFuture(future);
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof Message) {
            Message response = (Message) msg;
            log.info("Received from server: " + response.getContent());
        }
    }
}